package com.atguigu.myssm.ioc;

import com.atguigu.utils.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: ClassPathXmlApplicationContext
 * @Description:
 * @Author: wty
 * @Date: 2022/12/8
 */

public class ClassPathXmlApplicationContext implements BeanFactory {
    private Map<String, Object> beanMap = new HashMap<>();
    private String path = "applicationContext.xml";

    @Override
    public Object getBean(String id) {
        return beanMap.get(id);
    }

    public ClassPathXmlApplicationContext() {
        this("applicationContext.xml");
    }

    /**
     * @param
     * @return
     * @description //构造方法
     * @date 2022/12/8 10:49
     * @author wty
     **/
    public ClassPathXmlApplicationContext(String path) {
        if (StringUtils.isEmpty(path)) {
            throw new RuntimeException("IOC  配置文件未指定(ClassPathXmlApplicationContext)");
        }
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path);
        // 1.创建DocumentBuilderFactory
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        // 2.创建DocumentBuilder
        try {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            // 3.创建Document
            Document document = documentBuilder.parse(inputStream);

            // 4.获取所有的bean结点
            NodeList beanNodeList = document.getElementsByTagName("bean");

            for (int i = 0; i < beanNodeList.getLength(); i++) {
                Node beanNode = beanNodeList.item(i);
                if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");

                    // 创建bean对象和bean实例
                    Class<?> beanClass = Class.forName(className);
                    // 类对象
                    Object beanObject = beanClass.newInstance();

                    // 加入servletContext
                    //Field servletContextField = beanObj.getDeclaredField("servletContext");
                    //servletContextField.setAccessible(true);
                    //servletContextField.set(o, this.getServletContext());

                    //Method setServletContext = beanObj.getDeclaredMethod("setServletContext", ServletContext.class);
                    //setServletContext.invoke(o, this.getServletContext());

                    // 将bean对象保存到beanMap中
                    beanMap.put(beanId, beanObject);

                    // 到目前位置需要注意bean之间的依赖关系
                }
            }

            // 5. 组装bean之间的依赖关系
            for (int i = 0; i < beanNodeList.getLength(); i++) {
                Node beanNode = beanNodeList.item(i);
                if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");

                    NodeList beanchildNodeList = beanElement.getChildNodes();
                    System.out.println(beanchildNodeList.getLength());

                    for (int j = 0; j < beanchildNodeList.getLength(); j++) {
                        Node beanChildNode = beanchildNodeList.item(j);
                        /**
                         *
                         * Node 结点
                         *     Element 元素节点 sname
                         *     Text 文本节点 jim
                         * <sname>jim</sname>
                         *
                         */
                        if (beanChildNode.getNodeType() == Node.ELEMENT_NODE
                                && "property".equals(beanChildNode.getNodeName())) {
                            Element propertyElement = (Element) beanChildNode;
                            String propertyName = propertyElement.getAttribute("name");
                            String propertyref = propertyElement.getAttribute("ref");

                            // 1.找到propertyref对应的实例propertyName
                            Object refObject = beanMap.get(propertyref);
                            // 2.将refObject设置到当前bean对应的实例的property属性上
                            Object beanObject = beanMap.get(beanId);

                            Class<?> beanClass = beanObject.getClass();
                            Field propertyField = beanClass.getDeclaredField(propertyName);
                            propertyField.setAccessible(true);
                            propertyField.set(beanObject, refObject);
                        }
                    }

                }
            }


        } catch (ParserConfigurationException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
